package by.bsuir.m4a;

import java.math.BigDecimal;

public class Matrixes {
	
	public static final int COL_COUNT = 5;
	
	public static final int ROW_COUNT = 5;
	
	public static final int NUMBER_OF_DIGITS_AFTER_POINT = 4;
	
	public static final String NOT_TRIANGLE_MATRIX_MSG = "Target matrix can not be converted to triangle matrix";
	
	public static final String NO_ROOTS_MSG = "Hasn't roots";
	
	public static final String ALL_ROOTS_MSG = "Every number is a root";
	
	private int currentVariant;
	
	private double[][] matrixD = {{2.33, 0.81, 0.67, 0.92, -0.53},
						  {-0.53, 2.33, 0.81, 0.67, 0.92},
						  {0.92, -0.53, 2.33, 0.81, 0.67},
						  {0.67, 0.92, -0.53, 2.33, 0.81},
						  {0.81, 0.67, 0.92, -0.53, 2.33}};
	
	private double[][] matrixC = {{0.2, 0, 0.2, 0, 0},
						  {0, 0.2, 0, 0.2, 0},
						  {0.2, 0, 0.2, 0, 0.2},
						  {0, 0.2, 0, 0.2, 0},
						  {0, 0, 0.2, 0, 0.2}};
	
	private double[] vektorB = {4.2, 4.2, 4.2, 4.2, 4.2};
	
	private double[] vektorB1;
	
	private double[] vektorX = new double[COL_COUNT];
	
	private double[][] matrixA = new double[ROW_COUNT][COL_COUNT];
	
	public Matrixes(int variant) {
		currentVariant = variant;
		calculateA(variant);
	}
	
	private void calculateA(int variant) {
		for (int i = 0; i < ROW_COUNT; i++) {
			for (int j = 0; j < COL_COUNT; j++) {
				matrixA[i][j] = matrixC[i][j] * variant + matrixD[i][j];
			}
		}
	}
	
	private void calculateTriangleMatrix() throws InvalidMatrixException {
		double multiplyer;
		
		for (int i = 0; i < (ROW_COUNT - 1); i++) {
			if (matrixA[i][i] == 0) {
				reallocateRows(i);
			}
			for (int k = i + 1; k < ROW_COUNT; k++) {
				multiplyer = matrixA[k][i];
				for (int j = 0; j < COL_COUNT; j++) {
					matrixA[k][j]  -= (matrixA[i][j] / matrixA[i][i]) * multiplyer;
				}
				vektorB[k] -= (vektorB[i] / matrixA[i][i]) *  multiplyer;
			}
		}
	}
	
	private void reallocateRows(int rowIndex) throws InvalidMatrixException {
		int targetRowIndex = -1;
		double[] tempRow;
		
		for (int i = rowIndex + 1; i < ROW_COUNT; i++) {
			if (matrixA[i][rowIndex] != 0) {
				targetRowIndex = i;
				break;
			}
		}
		if (targetRowIndex != -1) {
			tempRow = matrixA[rowIndex];
			matrixA[rowIndex] = matrixA[targetRowIndex];
			matrixA[targetRowIndex] = tempRow;
		} else {
			throw new InvalidMatrixException(NOT_TRIANGLE_MATRIX_MSG);
		}	
	}
	
	private void calculateX() throws InvalidMatrixException {
		int sum;
		
		for (int i = ROW_COUNT - 1; i >= 0; i--) {
			sum = 0;
			for (int j = i + 1; j < ROW_COUNT; j++) {
				sum += matrixA[i][j];
			}
			vektorB[i] -= sum;
			if (matrixA[i][i] == 0) {
				vektorX = null;
				if (vektorB[i] != 0) {
					throw new InvalidMatrixException(NO_ROOTS_MSG);
				}
			} else {
				vektorX[i] = vektorB[i] / matrixA[i][i];
			}
			for (int j = i - 1; j >= 0; j--) {
				matrixA[j][i] *= vektorX[i];
			}
		}
	}
	
	public void calculate() {
		BigDecimal value;
		
		try {
			calculateTriangleMatrix();
			calculateX();
			for (int i = 0; i < COL_COUNT; i++) {
				value = BigDecimal.valueOf(vektorX[i]);
				value = value.setScale(NUMBER_OF_DIGITS_AFTER_POINT, BigDecimal.ROUND_HALF_UP);
				System.out.print(" " + value + " ");
			}
		} catch (InvalidMatrixException e) {
			System.out.println(e.getMessage());
		} catch (NullPointerException e) {
			System.out.println(ALL_ROOTS_MSG);
		}
	}
	
	public void checkRoots() {
		if (vektorX == null) {
			return;
		}
		calculateA(currentVariant);
		vektorB1 = new double[COL_COUNT];
		for (int i = 0; i < COL_COUNT; i++) {
			for (int j = 0; j < COL_COUNT; j++) {
				vektorB1[i] += matrixA[i][j] * vektorX[j];
			}
			System.out.print(" " + vektorB1[i] + " ");
		}
	}
			
	public static void main(String[] args) {
		Matrixes matrixes = new Matrixes(3);
		
		matrixes.calculate();
		matrixes.checkRoots();
	}

}
